package simpledb.execution;

import simpledb.common.DbException;
import simpledb.storage.Tuple;
import simpledb.storage.TupleDesc;
import simpledb.transaction.TransactionAbortedException;

import java.util.NoSuchElementException;

/**
 * Filter 是一个实现了关系型“选择”操作的查询执行算子。
 * 它按照指定的谓词条件对输入的元组流进行过滤，仅保留满足条件的元组，是数据库查询执行引擎中实现 WHERE 子句的核心组件。
 */
public class Filter extends Operator {

    private static final long serialVersionUID = 1L;

    // 过滤条件谓词，用于判断元组是否符合条件（如 age > 30、name = 'Alice' 等）
    private Predicate         predicate;

    // 子操作符（输入流），提供原始元组数据（如 SeqScan、Join 等算子的输出）
    private OpIterator        child;

    // 输出元组的描述信息，与子操作符的元组结构完全一致（过滤不改变字段定义）
    private TupleDesc         tupleDesc;

    /**
     * 构造函数：创建一个新的 Filter 算子。
     *
     * @param p 过滤谓词，定义过滤条件（如比较操作、逻辑操作等）
     * @param child 输入流算子，提供待过滤的原始元组
     */
    public Filter(Predicate p, OpIterator child) {
        this.predicate = p;
        this.child = child;
        this.tupleDesc = child.getTupleDesc(); // 输出结构与输入结构相同
    }

    /**
     * 获取当前 Filter 使用的谓词对象。
     */
    public Predicate getPredicate() {
        return this.predicate;
    }

    /**
     * 获取该操作符输出元组的描述信息。
     */
    public TupleDesc getTupleDesc() {
        return this.tupleDesc;
    }

    /**
     * 打开该操作符及其子操作符。
     */
    public void open() throws DbException, NoSuchElementException, TransactionAbortedException {
        child.open(); // 先打开子操作符
        super.open(); // 然后调用父类的 open 方法
    }

    /**
     * 关闭该操作符及其子操作符。
     */
    public void close() {
        child.close(); // 先关闭子操作符
        super.close(); // 再调用父类的 close 方法
    }

    /**
     * 将子操作符重置到初始状态，以便重新遍历数据。
     */
    public void rewind() throws DbException, TransactionAbortedException {
        child.rewind(); // 重置子操作符
    }

    /**
     * 实现 AbstractDbIterator 的 readNext 方法。
     * 从子操作符中逐个读取元组，并使用谓词进行过滤。
     * 只有满足谓词条件的元组才会被返回。
     *
     * @return 下一个满足条件的元组；如果没有更多元组则返回 null
     * @throws DbException
     * @throws TransactionAbortedException
     * @throws NoSuchElementException
     */
    protected Tuple fetchNext() throws NoSuchElementException, TransactionAbortedException, DbException {
        Tuple tuple;
        while (this.child.hasNext()) {
            tuple = this.child.next();
            if (tuple != null && this.predicate.filter(tuple)) {
                return tuple; // 返回第一个满足条件的元组
            }
        }
        return null; // 没有更多符合条件的元组
    }

    /**
     * 获取该操作符的所有子节点。
     * Filter 只有一个子操作符。
     */
    @Override
    public OpIterator[] getChildren() {
        return new OpIterator[] { this.child };
    }

    /**
     * 设置该操作符的子节点。
     * Filter 只能有一个子操作符。
     */
    @Override
    public void setChildren(OpIterator[] children) {
        this.child = children[0];
    }
}
